<?php
/*********************************************
Wrapper for the mail() function

Filename: mailparams.inc.php
Author: Oria Adam

License: GPLv3
http://softov.org/webdevtools


function mailparams($params)
	does :	Wrapper for mail() function
	notes:	Calling this function is much slower than directly calling mail(), so do not use it when bulk sending.
	     	In case of an error, the default error_log() is used with E_USER_WARNING and false is returned.
	     	This can be avoided with params['silent']=true.
	     	csv = string of comma separated values. Mostly it will be a simple string (single value)
	input:	Associative array with the following optional parameters:
		subject  - string. Mail subject. Up to 70 chars.
		msg/message/body - string. Mail body. Either html or plain text.
		html     - boolean. Is this an html body. Default: try to guess accoarding to message body (looking for '<html' / '<!doctype' / '<body').
		charset  - string. Character set of message body. Default: none (does not define a character set).
		from     - string. Email address this mail is sent from
		to       - csv or array. Email address(s) this mail is sent to. 
		cc       - csv or array. Email address(s) in the copy carbon field.
		bcc      - csv or array. Email address(s) in the hidden blank copy carbon field.
		replyto  - string. Email address to reply to this email. default: 'from' address
		headers  - string or array. Add this to the header of the email message
		file/files/attachment/attachements - csv or array of strings. A list of file name(s) to be attached to the email. If a file is missing, sending fails and false is returned
		test/simulate - boolean. Do not send the email, only test all params. Pay attention that this cannot assure that calling mail() function would work. currently this mode only check that all attached files exist, if any. Default false.
		silent   - boolean. In case of an error do not call error_log(), just quit and return false. Default false.
	output:	success true/false
*/

define('MAILPARAMS_MISSING_TO','undisclosed-emails@example.com');

function mailparams($params)
{
	if (empty($params['to']) && empty($params['cc']) && empty($params['bcc'])) {
		// no one to send to
		if (empty($params['silent'])) error_log('mailparams(): no one to send to',E_USER_WARNING);
		return false;
	}
	
	// black hat characters to remove
	$blackchars=array("\r","\n","\t");
	
	// set defaults
	//sender
	if (empty($params['from']) && !empty($params['sender'])) $params['from']=$params['sender'];
	if (empty($params['from'])) $params['from']='';
	else $params['from']=str_replace($blackchars,'',$params['from']);

	// reply to
	if (empty($params['replyto']) && !empty($params['reply'])) $params['replyto']=$params['reply'];
	if (empty($params['replyto'])) $params['replyto']=$params['from'];
	else $params['replyto']=str_replace($blackchars,'',$params['replyto']);
	
	//to
	if (empty($params['to'])) $params['to']=MAILPARAMS_MISSING_TO;
	else if (is_array($params['to'])) $params['to']=implode(',',$params['to']);
		else $params['to']=str_replace($blackchars,'',$params['to']);
	// To should have a Consistent format with double-qoutes: "name" <email@example.com>,"name2" <email2@example.com>
	$addresses = explode(',',$params['to']);
	for ($i=0;$i<count($addresses);$i++) {
		$v=str_replace($blackchars,'',$addresses[$i]);
		if (empty($v))
			unset($addresses[$i]);
		if (strpos($v,'<')) {
			$parts = explode('<',$v);
			if (count($parts)!=2) {
				if (empty($params['silent'])) error_log("mailparams(): bad `to`: ".htmlentities($v),E_USER_WARNING);
				return false;
			}
			$parts[0] = preg_replace('/["\']/',' ',$parts[0]); // remove all quotes
			$parts[0] = preg_replace('/^ +| +$/','',$parts[0]); // remove head/tail spaces
			$parts[1] = preg_replace('/[<>]/','',$parts[1]); // remove <> because i want to add them later
			$addresses[$i] = '"'.$parts[0].'" <'.$parts[1].'>'; // add double quotes
		}
	}
	$params['to']=implode(',',$addresses);
	$to = $addresses[0]; // $to is the first parameter of mail() - it can contain just one email address. the rest are in the headers.
	if (empty($to))
		$to=MAILPARAMS_MISSING_TO;
		
	//cc
	if (empty($params['cc'])) $params['cc']='';
	else if (is_array($params['cc'])) $params['cc']=implode(',',$params['cc']);
		else $params['cc']=str_replace($blackchars,'',$params['cc']);
	// Cc should have a Consistent format with double-qoutes: "name" <email@example.com>,"name2" <email2@example.com>
	$addresses = explode(',',$params['cc']);
	for ($i=0;$i<count($addresses);$i++) {
		$v=str_replace($blackchars,'',$addresses[$i]);
		if (empty($v))
			unset($addresses[$i]);
		if (strpos($v,'<')) {
			$parts = explode('<',$v);
			if (count($parts)!=2) {
				if (empty($params['silent'])) error_log("mailparams(): bad `cc`: ".htmlentities($v),E_USER_WARNING);
				return false;
			}
			$parts[0] = preg_replace('/["\']/',' ',$parts[0]); // remove all quotes
			$parts[0] = preg_replace('/^ +| +$/','',$parts[0]); // remove head/tail spaces
			$parts[1] = preg_replace('/[<>]/','',$parts[1]); // remove <> because i want to add them later
			$addresses[$i] = '"'.$parts[0].'" <'.$parts[1].'>'; // add double quotes
		}
	}
	$params['cc']=implode(',',$addresses);
		
	//bcc
	if (empty($params['bcc'])) $params['bcc']='';
	else if (is_array($params['bcc'])) $params['bcc']=implode(',',$params['bcc']);
		else $params['bcc']=str_replace($blackchars,'',$params['bcc']);
	// Bcc should have a Consistent format with double-qoutes: "name" <email@example.com>,"name2" <email2@example.com>
	$addresses = explode(',',$params['bcc']);
	for ($i=0;$i<count($addresses);$i++) {
		$v=str_replace($blackchars,'',$addresses[$i]);
		if (empty($v))
			unset($addresses[$i]);
		if (strpos($v,'<')) {
			$parts = explode('<',$v);
			if (count($parts)!=2) {
				if (empty($params['silent'])) error_log("mailparams(): bad `bcc`: ".htmlentities($v),E_USER_WARNING);
				return false;
			}
			$parts[0] = preg_replace('/["\']/',' ',$parts[0]); // remove all quotes
			$parts[0] = preg_replace('/^ +| +$/','',$parts[0]); // remove head/tail spaces
			$parts[1] = preg_replace('/[<>]/','',$parts[1]); // remove <> because i want to add them later
			$addresses[$i] = '"'.$parts[0].'" <'.$parts[1].'>'; // add double quotes
		}
	}
	$params['bcc']=implode(',',$addresses);
	
	//subject
	if (empty($params['subject'])) $params['subject']='';
	else $params['subject']=substr(str_replace($blackchars,'',$params['subject']),0,70);
	
	// message body
	if (empty($params['body']) && !empty($params['message'])) $params['body']=$params['message'];
	if (empty($params['body']) && !empty($params['msg'    ])) $params['body']=$params['msg'];
	if (empty($params['body'])) $params['body']='';
	else $params['body']=wordwrap($params['body'],70);

	// html
	if (!isset($params['html'])) $params['html'] = (stripos($params['body'],'<!DOCTYPE HTML')!==false)
										||(stripos($params['body'],'<html')!==false)
										||(stripos($params['body'],'<body')!==false);
	
	// charset
	if (empty($params['charset'])) $params['charset']='';
	
	// attachements
	if (empty($params['files']) && !empty($params['file'])) $params['files']=$params['file'];
	if (empty($params['files']) && !empty($params['attachment'])) $params['files']=$params['attachment'];
	if (empty($params['files']) && !empty($params['attachments'])) $params['files']=$params['attachments'];
	if (empty($params['files'])) $params['files']=array();
	else if (!is_array($params['files'])) $params['files']=explode(',',$params['files']);

	// headers
	if (empty($params['headers']) && !empty($params['moreheaders'])) $params['headers']=$params['moreheaders'];
	if (!empty($params['headers']) && is_array($parms['headers'])) $params['headers']=implode("\r\n",$params['headers']);
	$headers = '';
	$headers .= "To: $params[to]\r\n";
	$headers .= "From: $params[from]\r\n";
	$headers .= "Reply-To: $params[replyto]\r\n";
	if (!empty($params['cc'])) $headers .= "Cc: $params[cc]\r\n";
	if (!empty($params['bcc'])) $headers .= "Bcc: $params[bcc]\r\n";

	// attach files -- based on a script by "Anda" from http://php.net/mail
	if (count($params['files'])) {
		$files=$params['files'];
		// boundary
		$semi_rand = md5(time());
		$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";

		// headers for attachment
		$headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";

		// multipart boundary
		$message = "--{$mime_boundary}\n";
		if ($params['html']) {
			$message .= 'Content-type: text/html; ' . (empty($params['charset'])?'':"charset=$params[charset]") . "\r\n";
		} else {
			$message .= 'Content-Type: text/plain;' . (empty($params['charset'])?'':"charset=$params[charset]") . "\r\n";
		}
		$message .= "Content-Transfer-Encoding: base64\n\n" . base64_encode($params['body']) . "\n\n";

		// preparing attachments
		for($i=0;$i<count($files);$i++) {
			if (is_file($files[$i])) {
				$message .= "--{$mime_boundary}\n";
				$fp =    @fopen($files[$i],"rb");
				$data =    @fread($fp,filesize($files[$i]));
				@fclose($fp);
				$data = chunk_split(base64_encode($data));
				$message .= "Content-Type: application/octet-stream; name=\"".basename($files[$i])."\"\n" . 
				"Content-Description: ".basename($files[$i])."\n" .
				"Content-Disposition: attachment;\n" . " filename=\"".basename($files[$i])."\"; size=".filesize($files[$i]).";\n" . 
				"Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
			} else {
				if (empty($params['silent'])) error_log("mailparams(): attached file: ".htmlentities($files[$i]),E_USER_WARNING);
				return false;
			}
		}
		$message .= "--{$mime_boundary}--";

		$params['body']=$message;
	
	} else { // if files
	
		// Each of these 3 lines cause the mail to be send wrong. the html becomes text and the headers are inside the visible message body.
		//$headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
		//if ($html) $headers .= 'MIME-Version: 1.0' . "\r\n";
		if ($params['html']) {
			$headers  = 'MIME-Version: 1.0' . "\r\n";
			$headers .= 'Content-type: text/html; ' . (empty($params['charset'])?'':"charset=$params[charset]") . "\r\n";
		}
	}
	
	
	if (!empty($params['sensitivity'])) $headers.="Sensitivity: $params[sensitivity]\r\n";
	if (!empty($params['headers'])) $headers .= $params['headers'];
	
	$headers = preg_replace('/^[\\n\\r]+|[\\n\\r]+$/','',$headers); // remove blank lines from head and tail
	$headers = preg_replace('/\\n\\r\\n\\r$/',"\n\r",$headers); // join together doubled blank lines
	$headers = $headers."\r\n"; // restore the blank lines to tail

	if (empty($params['simulate']) && empty($params['test'])) {
		return mail($to,$params['subject'],$params['body'],$headers,'-f'.$params['from']);
	} else {
		return true;
	}
}

